﻿// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System.Threading;
using System.Threading.Tasks;

namespace SnapObjects.Data
{
    internal class QueryBuilder<TModel> : IQueryBuilder<TModel>
    {
        private readonly ISqlBuilderLoader<TModel> _loader;
        private readonly ISqlQueryBuilder _queryBuilder;

        public QueryBuilder(DataContext context, bool removeWhereCluase)
        {
            var modelSelect = new ModelSelectBuilder(context);

            _queryBuilder = modelSelect.GetModelQueryBuilder(typeof(TModel)).SqlQueryBuilder;

            _loader = new SqlBuilderLoader<TModel>(context, _queryBuilder);

            if (removeWhereCluase)
            {
                _queryBuilder.RemoveWhere();
            }
        }

        public ILoadable<TModel> Load(params object[] parameters)
        {
            return _loader.Load(parameters);
        }

        public Task<ILoadable<TModel>> LoadAsync(CancellationToken cancellationToken)
        {
            return _loader.LoadAsync(cancellationToken);
        }

        public Task<ILoadable<TModel>> LoadAsync(
            object[] parameters, CancellationToken cancellationToken)
        {
            return _loader.LoadAsync(parameters, cancellationToken);
        }

        public Task<ILoadable<TModel>> LoadAsync(params object[] parameters)
        {
            return _loader.LoadAsync(parameters);
        }

        public ILoadable<TModel> LoadByPage(
            int currentIndex, int pageSize, params object[] parameters)
        {
            return _loader.LoadByPage(currentIndex, pageSize, parameters);
        }

        public Task<ILoadable<TModel>> LoadByPageAsync(
            int currentIndex, int pageSize, CancellationToken cancellationToken)
        {
            return _loader.LoadByPageAsync(currentIndex, pageSize, cancellationToken);
        }

        public Task<ILoadable<TModel>> LoadByPageAsync(
            int currentIndex, int pageSize, params object[] parameters)
        {
            return _loader.LoadByPageAsync(currentIndex, pageSize, parameters);
        }

        public Task<ILoadable<TModel>> LoadByPageAsync(
            int currentIndex, int pageSize, object[] parameters, CancellationToken cancellationToken)
        {
            return _loader.LoadByPageAsync(currentIndex, pageSize, parameters, cancellationToken);
        }

        public IQueryAndOrBuilder<TModel> AndWhere(string left, ISqlParameter parameter)
        {
            _queryBuilder.AsWhere().AndWhere(left, parameter);

            return this;
        }

        public IQueryAndOrBuilder<TModel> AndWhere(
            string left, SqlBinaryOperator sqlOperator, ISqlParameter parameter)
        {
            _queryBuilder.AsWhere().AndWhere(left, sqlOperator, parameter);

            return this;
        }

        public IQueryAndOrBuilder<TModel> AndWhere(string left, string right)
        {
            _queryBuilder.AsWhere().AndWhere(left, right);

            return this;
        }

        public IQueryAndOrBuilder<TModel> AndWhere(
            string left, SqlBinaryOperator sqlOperator, string right)
        {
            _queryBuilder.AsWhere().AndWhere(left, sqlOperator, right);

            return this;
        }

        public IQueryAndOrBuilder<TModel> AndWhere(string left, ISqlBuilder sqlBuilder)
        {
            _queryBuilder.AsWhere().AndWhere(left, sqlBuilder);

            return this;
        }

        public IQueryAndOrBuilder<TModel> AndWhere(
            string left, SqlBinaryOperator sqlOperator, ISqlBuilder sqlBuilder)
        {
            _queryBuilder.AsWhere().AndWhere(left, sqlOperator, sqlBuilder);

            return this;
        }

        public IQueryAndOrBuilder<TModel> AndWhere(ISqlWhereCondition condition)
        {
            _queryBuilder.AsWhere().AndWhere(condition);

            return this;
        }

        public IQueryAndOrBuilder<TModel> AndWhereExists(ISqlBuilder sqlBuilder)
        {
            _queryBuilder.AsWhere().AndWhereExists(sqlBuilder);

            return this;
        }

        public IQueryAndOrBuilder<TModel> AndWhereIsNotNull(string left)
        {
            _queryBuilder.AsWhere().AndWhereIsNotNull(left);

            return this;
        }

        public IQueryAndOrBuilder<TModel> AndWhereIsNull(string left)
        {
            _queryBuilder.AsWhere().AndWhereIsNull(left);

            return this;
        }

        public IQueryAndOrBuilder<TModel> AndWhereNotExists(ISqlBuilder sqlBuilder)
        {
            _queryBuilder.AsWhere().AndWhereNotExists(sqlBuilder);

            return this;
        }

        public IQueryAndOrBuilder<TModel> AndWhereRaw(string clause, params ISqlParameter[] parameters)
        {
            _queryBuilder.AsWhere().AndWhereRaw(clause, parameters);

            return this;
        }

        public IQueryAndOrBuilder<TModel> AndWhereValue(string left, object value)
        {
            _queryBuilder.AsWhere().AndWhereValue(left, value);

            return this;
        }

        public IQueryAndOrBuilder<TModel> AndWhereValue(
            string left, SqlBinaryOperator sqlOperator, object value)
        {
            _queryBuilder.AsWhere().AndWhereValue(left, sqlOperator, value);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhere(string left, ISqlParameter parameter)
        {
            _queryBuilder.AsWhere().OrWhere(left, parameter);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhere(
            string left, SqlBinaryOperator sqlOperator, ISqlParameter parameter)
        {
            _queryBuilder.AsWhere().OrWhere(left, sqlOperator, parameter);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhere(string left, string right)
        {
            _queryBuilder.AsWhere().OrWhere(left, right);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhere(
            string left, SqlBinaryOperator sqlOperator, string right)
        {
            _queryBuilder.AsWhere().OrWhere(left, sqlOperator, right);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhere(string left, ISqlBuilder sqlBuilder)
        {
            _queryBuilder.AsWhere().OrWhere(left, sqlBuilder);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhere(
            string left, SqlBinaryOperator sqlOperator, ISqlBuilder sqlBuilder)
        {
            _queryBuilder.AsWhere().OrWhere(left, sqlOperator, sqlBuilder);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhere(ISqlWhereCondition condition)
        {
            _queryBuilder.AsWhere().OrWhere(condition);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhereExists(ISqlBuilder sqlBuilder)
        {
            _queryBuilder.AsWhere().OrWhereExists(sqlBuilder);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhereIsNotNull(string left)
        {
            _queryBuilder.AsWhere().OrWhereIsNotNull(left);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhereIsNull(string left)
        {
            _queryBuilder.AsWhere().OrWhereIsNull(left);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhereNotExists(ISqlBuilder sqlBuilder)
        {
            _queryBuilder.AsWhere().OrWhereNotExists(sqlBuilder);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhereRaw(string clause, params ISqlParameter[] parameters)
        {
            _queryBuilder.AsWhere().OrWhereRaw(clause, parameters);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhereValue(string left, object value)
        {
            _queryBuilder.AsWhere().OrWhereValue(left, value);

            return this;
        }

        public IQueryAndOrBuilder<TModel> OrWhereValue(
            string left, SqlBinaryOperator sqlOperator, object value)
        {
            _queryBuilder.AsWhere().OrWhereValue(left, sqlOperator, value);

            return this;
        }

        public IQueryWhereBuilder<TModel> RemoveWhere()
        {
            _queryBuilder.RemoveWhere();

            return this;
        }

        public IQueryAndOrBuilder<TModel> Where(string left, ISqlParameter parameter)
        {
            _queryBuilder.Where(left, parameter);

            return this;
        }

        public IQueryAndOrBuilder<TModel> Where(
            string left, SqlBinaryOperator sqlOperator, ISqlParameter parameter)
        {
            _queryBuilder.Where(left, sqlOperator, parameter);

            return this;
        }

        public IQueryAndOrBuilder<TModel> Where(string left, string right)
        {
            _queryBuilder.Where(left, right);

            return this;
        }

        public IQueryAndOrBuilder<TModel> Where(
            string left, SqlBinaryOperator sqlOperator, string right)
        {
            _queryBuilder.Where(left, sqlOperator, right);

            return this;
        }

        public IQueryAndOrBuilder<TModel> Where(string left, ISqlBuilder sqlBuilder)
        {
            _queryBuilder.Where(left, sqlBuilder);

            return this;
        }

        public IQueryAndOrBuilder<TModel> Where(
            string left, SqlBinaryOperator sqlOperator, ISqlBuilder sqlBuilder)
        {
            _queryBuilder.Where(left, sqlOperator, sqlBuilder);

            return this;
        }

        public IQueryAndOrBuilder<TModel> Where(ISqlWhereCondition condition)
        {
            _queryBuilder.Where(condition);

            return this;
        }

        public IQueryAndOrBuilder<TModel> WhereExists(ISqlBuilder sqlBuilder)
        {
            _queryBuilder.WhereExists(sqlBuilder);

            return this;
        }

        public IQueryAndOrBuilder<TModel> WhereIsNotNull(string left)
        {
            _queryBuilder.WhereIsNotNull(left);

            return this;
        }

        public IQueryAndOrBuilder<TModel> WhereIsNull(string left)
        {
            _queryBuilder.WhereIsNull(left);

            return this;
        }

        public IQueryAndOrBuilder<TModel> WhereNotExists(ISqlBuilder sqlBuilder)
        {
            _queryBuilder.WhereNotExists(sqlBuilder);

            return this;
        }

        public IQueryAndOrBuilder<TModel> WhereRaw(
            string whereClause, params ISqlParameter[] parameters)
        {
            _queryBuilder.WhereRaw(whereClause, parameters);

            return this;
        }

        public IQueryAndOrBuilder<TModel> WhereValue(string left, object value)
        {
            _queryBuilder.WhereValue(left, value);

            return this;
        }

        public IQueryAndOrBuilder<TModel> WhereValue(
            string left, SqlBinaryOperator sqlOperator, object value)
        {
            _queryBuilder.WhereValue(left, sqlOperator, value);

            return this;
        }
    }
}
